// 7.4 类的作用域
/**
 * 在类的作用域之外，普通的数据和函数成员只能由对象、引用或者指针使用成员访问运算符（参见4.6节，第133页）来访问。
 * 
 * 7.4.1　名字查找与类的作用域
 * 编译器处理完类中的全部声明后才会处理成员函数的定义。
 * 尽管重新定义类型名字是一种错误的行为，但是编译器并不为此负责。一些编译器仍将顺利通过这样的代码，而忽略代码有错的事实。
 * 类型名的定义通常出现在类的开始处，这样就能确保所有使用该类型的成员都出现在类名的定义之后。
 */

#include <iostream>
#include <vector>
#include "Sales_data.h"
//#include "Screen.h" // 难道是因为Window_mgr被声明成Screen的友元的原因？导致这个源文件同时包含这两个头文件时会导致一些问题？
#include "WindowMgr.h"
using std::cerr, std::clog;
using std::cin, std::cout, std::endl;

// 一旦遇到了类名，定义的剩余部分就在类的作用域之内了，这里的剩余部分包括参数列表和函数体。 
// void Window_mgr::clear(ScreenIndex i)
// {
//     Screen &s = screens[i];
//     s.contents = string(s.height * s.width, ' ');
// }

// 当成员函数定义在类的外部时，返回类型中使用的名字都位于类的作用域之外。这时，返回类型必须指明它是哪个类的成员。
// 当在7.4.cc中同时包含Screen.h和WindowMgr.h时，该函数报错：
// declaration is incompatible with "Window_mgr::ScreenIndex Window_mgr::addScreen(const <error-type> &s)" (declared at line 44 of "D:\MYSTUDY\C++\C++PRIMER5\CHATPER07\WindowMgr.h")C/C++(147)
// Window_mgr::ScreenIndex Window_mgr::addScreen(const Screen &s)
// {
//     screens.push_back(s);
//     return screens.size() - 1;
// }


// 用于类成员声明的名字查找：
// 如果某个成员的声明使用了类中尚未出现的名字，则编译器将会在定义该类的作用域中继续查找。
typedef double Money;
string bal;
class Account
{
public:
    Money blance() { return bal;}
private:
    // 尽管重新定义类型名字是一种错误的行为，但是编译器并不为此负责。一些编译器仍将顺利通过这样的代码，而忽略代码有错的事实
    typedef double Money; // 错误，不能重新定义Money
    Money bal;
};

// 类型名要特殊处理
// 在类中，如果成员使用了外层作用域中的某个名字，而该名字代表一种类型，则类不能在之后重新定义该名字

int main()
{
    // 作用域和定义在类外部的成员
    // 例如定义Screen类内的pos，需要使用::作用域运算符
    // 因为在Screen类外pos是不可见的
    Screen::pos ht = 24, wd = 80; // 使用Screen定义的pos类型
    Screen scr(ht, wd, ' ');
    Screen *p = &scr;
    char c = scr.get(); // 访问scr对象的get成员
    c = p->get();       // 访问p所指对象的get成员



    return 0;
}